package main

import (
	"fmt"
)

type AstPrinter struct{}

func (ap *AstPrinter) print(e *Expr) interface{} {
	return (*e).accept(ap)
}

func (ap *AstPrinter) parenthesize(op string, exprs ...Expr) string {
	var r string = "(" + op
	for _, exp := range exprs {
		r += fmt.Sprintf(" %v", exp.accept(ap).(string))
	}
	r += ")"
	return r
}

func (ap *AstPrinter) visitBinary(e *Binary) interface{} {
	return ap.parenthesize(e.operator.Value, e.left, e.right)
}

func (ap *AstPrinter) visitGrouping(e *Grouping) interface{} {
	return ap.parenthesize("group", e.expression)
}

func (*AstPrinter) visitLiteral(e *Literal) interface{} {
	if e.value == nil {
		return "nil"
	}
	return fmt.Sprintf("%v", e.value)
}

func (ap *AstPrinter) visitUnary(e *Unary) interface{} {
	return ap.parenthesize(e.operator.Value, e.right)
}
